In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from scipy import stats
import re
from datetime import datetime, timedelta
import warnings
# Suppress warnings
warnings.filterwarnings('ignore')
# Set better visualization defaults
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_context("notebook", font_scale=1.1)
plt.rcParams['figure.figsize'] = [12, 8]
plt.rcParams['figure.dpi'] = 100
# Enable interactive plotly figures in the notebook
import plotly.io as pio
pio.renderers.default = "notebook"
1. Data Loading and Initial Preprocessing¶
Loading the CSV data and performing initial preprocessing steps.
In [2]:
# Read the data
data_path = 'data/chapter7'
df = pd.read_csv(data_path + '/x1-plant-20250407-20250414.csv')
# Display basic information
print(f"Dataset shape: {df.shape}")
print(f"Number of records: {df.shape[0]}")
print(f"Number of features: {df.shape[1]}")
# Show the first few rows
df.head()
Dataset shape: (10000, 26) Number of records: 10000 Number of features: 26
Out[2]:
| Timestamp | 1A-HVP-CHW_FM_m13c7 | 1A-HVP-CHW_P-VFD-SPD-COMMAND_m3c12 | 1A-HVP-CHW_SupplyTemp_m13c5 | 1A-HVP-HW_FM_m13c2 | 1A-HVP-HW_MV-POSN_m14c0 | 1A-HVP-HW_P-VFD-SPD-COMMAND_m3c11 | 1A-HVP-HW_ReturnTemp_m13c1 | 1-PLT-HW_ReturnTemp_m4c1 | 1A-HVP-CHW_MV-POSN_m14c1 | ... | 1B-HVP-CHW_SupplyTemp_m13c5 | 1B-HVP-HW_FM_m13c2 | 1B-HVP-HW_MV-POSN_m14c0 | 1B-HVP-HW_P-VFD-SPD-COMMAND_m3c11 | 1B-HVP-HW_ReturnTemp_m13c1 | 1B-HVP-HW_SupplyTemp_m13c0 | 1-PLT-CHW_FM_m5c4 | 1-PLT-CHW_ReturnTemp_m5c1 | 1-PLT-CHW_SupplyTemp_m5c0 | 1-PLT-HW_SupplyTemp_m4c0 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2025-04-06T23:59:00-08:00 GMT+8 | -0.003750 | 70.0 | 11.805918 | 8.635705 | 74.989067 | 70 | 54.160069 | 57.982452 | 75.216293 | ... | 10.475084 | 7.914548 | 74.408501 | 70.0 | 56.044308 | 59.208015 | 31.442701 | 10.697201 | 10.818849 | 59.223995 |
| 1 | 2025-04-07T00:00:00-08:00 GMT+8 | -0.003838 | 70.0 | 11.808234 | 8.636075 | 74.995178 | 70 | 54.248199 | 58.051712 | 75.209885 | ... | 10.475075 | 7.913702 | 74.410736 | 70.0 | 56.079254 | 59.214706 | 31.465260 | 10.720372 | 10.842798 | 59.244759 |
| 2 | 2025-04-07T00:01:00-08:00 GMT+8 | -0.003733 | 70.0 | 11.812600 | 8.638296 | 74.981544 | 70 | 54.303020 | 58.057404 | 75.196541 | ... | 10.478762 | 7.914269 | 74.411751 | 70.0 | 56.103672 | 59.236362 | 31.461641 | 10.738330 | 10.871675 | 59.228104 |
| 3 | 2025-04-07T00:02:00-08:00 GMT+8 | -0.003612 | 70.0 | 11.816528 | 8.638912 | 75.000549 | 70 | 54.290234 | 58.038849 | 75.211548 | ... | 10.484300 | 7.914650 | 74.416122 | 70.0 | 56.126537 | 59.208504 | 31.474689 | 10.766316 | 10.896990 | 59.096451 |
| 4 | 2025-04-07T00:03:00-08:00 GMT+8 | -0.003703 | 70.0 | 11.821356 | 8.637137 | 74.992912 | 70 | 54.310200 | 58.038498 | 75.205727 | ... | 10.492901 | 7.913052 | 74.423698 | 70.0 | 56.162067 | 59.101505 | 31.463257 | 10.815225 | 10.933206 | 59.011921 |
5 rows × 26 columns
1.1 Data Preprocessing¶
In [3]:
# Convert timestamp to datetime
df['Timestamp'] = pd.to_datetime(df['Timestamp'].str.replace(' GMT+8', ''))
df.set_index('Timestamp', inplace=True)
# Create a dictionary to map original column names to simplified names
def simplify_column_name(col_name):
# Extract building (1A, 1B, 1-PLT)
building_match = re.match(r'(1[A|B]|1-PLT)', col_name)
building = building_match.group(1) if building_match else ""
# Extract system type (CHW, HW)
system_match = re.search(r'(CHW|HW)', col_name)
system = system_match.group(1) if system_match else ""
# Extract measurement type
if 'FM' in col_name:
measure = 'FlowRate'
elif 'VFD' in col_name:
measure = 'PumpSpeed'
elif 'MV-POSN' in col_name:
measure = 'ValvePosition'
elif 'SupplyTemp' in col_name:
measure = 'SupplyTemp'
elif 'ReturnTemp' in col_name:
measure = 'ReturnTemp'
else:
measure = col_name.split('_')[-1]
return f"{building}_{system}_{measure}"
column_mapping = {col: simplify_column_name(col) for col in df.columns}
df.rename(columns=column_mapping, inplace=True)
# Create a dictionary to store the appropriate units for each column
units = {
# Flow rates
'1A_CHW_FlowRate': 'L/min',
'1B_CHW_FlowRate': 'L/min',
'1A_HW_FlowRate': 'L/min',
'1B_HW_FlowRate': 'L/min',
'1-PLT_CHW_FlowRate': 'L/min',
# Temperatures
'1A_CHW_SupplyTemp': '°C',
'1A_CHW_ReturnTemp': '°C',
'1B_CHW_SupplyTemp': '°C',
'1B_CHW_ReturnTemp': '°C',
'1A_HW_SupplyTemp': '°C',
'1A_HW_ReturnTemp': '°C',
'1B_HW_SupplyTemp': '°C',
'1B_HW_ReturnTemp': '°C',
'1-PLT_CHW_SupplyTemp': '°C',
'1-PLT_CHW_ReturnTemp': '°C',
'1-PLT_HW_SupplyTemp': '°C',
'1-PLT_HW_ReturnTemp': '°C',
# Valve positions and pump speeds
'1A_CHW_ValvePosition': '%',
'1B_CHW_ValvePosition': '%',
'1A_HW_ValvePosition': '%',
'1B_HW_ValvePosition': '%',
'1A_CHW_PumpSpeed': '%',
'1B_CHW_PumpSpeed': '%',
'1A_HW_PumpSpeed': '%',
'1B_HW_PumpSpeed': '%'
}
# Display the column mapping
print("Column mapping:")
for original, new in column_mapping.items():
print(f" {original} -> {new}")
# Display the renamed dataframe
df.head()
Column mapping: 1A-HVP-CHW_FM_m13c7 -> 1A_CHW_FlowRate 1A-HVP-CHW_P-VFD-SPD-COMMAND_m3c12 -> 1A_CHW_PumpSpeed 1A-HVP-CHW_SupplyTemp_m13c5 -> 1A_CHW_SupplyTemp 1A-HVP-HW_FM_m13c2 -> 1A_HW_FlowRate 1A-HVP-HW_MV-POSN_m14c0 -> 1A_HW_ValvePosition 1A-HVP-HW_P-VFD-SPD-COMMAND_m3c11 -> 1A_HW_PumpSpeed 1A-HVP-HW_ReturnTemp_m13c1 -> 1A_HW_ReturnTemp 1-PLT-HW_ReturnTemp_m4c1 -> 1-PLT_HW_ReturnTemp 1A-HVP-CHW_MV-POSN_m14c1 -> 1A_CHW_ValvePosition 1A-HVP-CHW_ReturnTemp_m13c6 -> 1A_CHW_ReturnTemp 1A-HVP-HW_SupplyTemp_m13c0 -> 1A_HW_SupplyTemp 1B-HVP-CHW_FM_m13c7 -> 1B_CHW_FlowRate 1B-HVP-CHW_MV-POSN_m14c1 -> 1B_CHW_ValvePosition 1B-HVP-CHW_P-VFD-SPD-COMMAND_m3c12 -> 1B_CHW_PumpSpeed 1B-HVP-CHW_ReturnTemp_m13c6 -> 1B_CHW_ReturnTemp 1B-HVP-CHW_SupplyTemp_m13c5 -> 1B_CHW_SupplyTemp 1B-HVP-HW_FM_m13c2 -> 1B_HW_FlowRate 1B-HVP-HW_MV-POSN_m14c0 -> 1B_HW_ValvePosition 1B-HVP-HW_P-VFD-SPD-COMMAND_m3c11 -> 1B_HW_PumpSpeed 1B-HVP-HW_ReturnTemp_m13c1 -> 1B_HW_ReturnTemp 1B-HVP-HW_SupplyTemp_m13c0 -> 1B_HW_SupplyTemp 1-PLT-CHW_FM_m5c4 -> 1-PLT_CHW_FlowRate 1-PLT-CHW_ReturnTemp_m5c1 -> 1-PLT_CHW_ReturnTemp 1-PLT-CHW_SupplyTemp_m5c0 -> 1-PLT_CHW_SupplyTemp 1-PLT-HW_SupplyTemp_m4c0 -> 1-PLT_HW_SupplyTemp
Out[3]:
| 1A_CHW_FlowRate | 1A_CHW_PumpSpeed | 1A_CHW_SupplyTemp | 1A_HW_FlowRate | 1A_HW_ValvePosition | 1A_HW_PumpSpeed | 1A_HW_ReturnTemp | 1-PLT_HW_ReturnTemp | 1A_CHW_ValvePosition | 1A_CHW_ReturnTemp | ... | 1B_CHW_SupplyTemp | 1B_HW_FlowRate | 1B_HW_ValvePosition | 1B_HW_PumpSpeed | 1B_HW_ReturnTemp | 1B_HW_SupplyTemp | 1-PLT_CHW_FlowRate | 1-PLT_CHW_ReturnTemp | 1-PLT_CHW_SupplyTemp | 1-PLT_HW_SupplyTemp | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Timestamp | |||||||||||||||||||||
| 2025-04-06 23:59:00-08:00 | -0.003750 | 70.0 | 11.805918 | 8.635705 | 74.989067 | 70 | 54.160069 | 57.982452 | 75.216293 | 13.339764 | ... | 10.475084 | 7.914548 | 74.408501 | 70.0 | 56.044308 | 59.208015 | 31.442701 | 10.697201 | 10.818849 | 59.223995 |
| 2025-04-07 00:00:00-08:00 | -0.003838 | 70.0 | 11.808234 | 8.636075 | 74.995178 | 70 | 54.248199 | 58.051712 | 75.209885 | 13.339400 | ... | 10.475075 | 7.913702 | 74.410736 | 70.0 | 56.079254 | 59.214706 | 31.465260 | 10.720372 | 10.842798 | 59.244759 |
| 2025-04-07 00:01:00-08:00 | -0.003733 | 70.0 | 11.812600 | 8.638296 | 74.981544 | 70 | 54.303020 | 58.057404 | 75.196541 | 13.339435 | ... | 10.478762 | 7.914269 | 74.411751 | 70.0 | 56.103672 | 59.236362 | 31.461641 | 10.738330 | 10.871675 | 59.228104 |
| 2025-04-07 00:02:00-08:00 | -0.003612 | 70.0 | 11.816528 | 8.638912 | 75.000549 | 70 | 54.290234 | 58.038849 | 75.211548 | 13.337449 | ... | 10.484300 | 7.914650 | 74.416122 | 70.0 | 56.126537 | 59.208504 | 31.474689 | 10.766316 | 10.896990 | 59.096451 |
| 2025-04-07 00:03:00-08:00 | -0.003703 | 70.0 | 11.821356 | 8.637137 | 74.992912 | 70 | 54.310200 | 58.038498 | 75.205727 | 13.337246 | ... | 10.492901 | 7.913052 | 74.423698 | 70.0 | 56.162067 | 59.101505 | 31.463257 | 10.815225 | 10.933206 | 59.011921 |
5 rows × 25 columns
1.2 Calculate Derived Performance Metrics¶
Calculate key performance metrics for each system, including:
- Delta T (temperature difference between supply and return)
- Energy transfer rates
- System efficiency
In [4]:
# Calculate delta T for each system
for building in ['1A', '1B', '1-PLT']:
# Chilled Water Delta T
if f'{building}_CHW_SupplyTemp' in df.columns and f'{building}_CHW_ReturnTemp' in df.columns:
df[f'{building}_CHW_DeltaT'] = df[f'{building}_CHW_ReturnTemp'] - df[f'{building}_CHW_SupplyTemp']
# Hot Water Delta T
if f'{building}_HW_SupplyTemp' in df.columns and f'{building}_HW_ReturnTemp' in df.columns:
df[f'{building}_HW_DeltaT'] = df[f'{building}_HW_SupplyTemp'] - df[f'{building}_HW_ReturnTemp']
# Calculate energy transfer rates (in kW)
# Specific heat of water: 4.186 kJ/kg·°C
# Density of water: 1 kg/L
# Flow rate is in L/min, so we divide by 60 to get L/s
# Energy (kW) = flow rate (L/s) * specific heat (kJ/kg·°C) * density (kg/L) * delta T (°C)
for building in ['1A', '1B']:
# CHW Energy Transfer
if f'{building}_CHW_FlowRate' in df.columns and f'{building}_CHW_DeltaT' in df.columns:
df[f'{building}_CHW_Energy'] = abs(df[f'{building}_CHW_FlowRate'] / 60 * 4.186 * df[f'{building}_CHW_DeltaT'])
# HW Energy Transfer
if f'{building}_HW_FlowRate' in df.columns and f'{building}_HW_DeltaT' in df.columns:
df[f'{building}_HW_Energy'] = abs(df[f'{building}_HW_FlowRate'] / 60 * 4.186 * df[f'{building}_HW_DeltaT'])
# Calculate plant energy transfer
if '1-PLT_CHW_FlowRate' in df.columns and '1-PLT_CHW_DeltaT' in df.columns:
df['1-PLT_CHW_Energy'] = abs(df['1-PLT_CHW_FlowRate'] / 60 * 4.186 * df['1-PLT_CHW_DeltaT'])
# Calculate system efficiency (as a ratio of energy delivered to energy produced)
# For chilled water
total_chw_delivered = df.get('1A_CHW_Energy', 0) + df.get('1B_CHW_Energy', 0)
if '1-PLT_CHW_Energy' in df.columns and df['1-PLT_CHW_Energy'].mean() != 0:
df['CHW_Distribution_Efficiency'] = (total_chw_delivered / df['1-PLT_CHW_Energy']).replace([np.inf, -np.inf, np.nan], 0)
# Display the derived metrics
print("\nDerived performance metrics:")
derived_metrics = [col for col in df.columns if 'Delta' in col or 'Energy' in col or 'Efficiency' in col]
df[derived_metrics].head()
Derived performance metrics:
Out[4]:
| 1A_CHW_DeltaT | 1A_HW_DeltaT | 1B_CHW_DeltaT | 1B_HW_DeltaT | 1-PLT_CHW_DeltaT | 1-PLT_HW_DeltaT | 1A_CHW_Energy | 1A_HW_Energy | 1B_CHW_Energy | 1B_HW_Energy | 1-PLT_CHW_Energy | CHW_Distribution_Efficiency | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Timestamp | ||||||||||||
| 2025-04-06 23:59:00-08:00 | 1.533846 | 2.392223 | 0.743413 | 3.163708 | -0.121648 | 1.241543 | 0.000401 | 1.441277 | 0.000242 | 1.746910 | 0.266853 | 0.002410 |
| 2025-04-07 00:00:00-08:00 | 1.531166 | 2.339504 | 0.742417 | 3.135452 | -0.122426 | 1.193047 | 0.000410 | 1.409575 | 0.000150 | 1.731123 | 0.268753 | 0.002084 |
| 2025-04-07 00:01:00-08:00 | 1.526834 | 2.317551 | 0.740699 | 3.132690 | -0.133346 | 1.170700 | 0.000398 | 1.396707 | 0.000209 | 1.729722 | 0.292690 | 0.002072 |
| 2025-04-07 00:02:00-08:00 | 1.520921 | 2.305969 | 0.742099 | 3.081966 | -0.130673 | 1.057602 | 0.000383 | 1.389826 | 0.000179 | 1.701796 | 0.286944 | 0.001959 |
| 2025-04-07 00:03:00-08:00 | 1.515890 | 2.213482 | 0.743318 | 2.939438 | -0.117981 | 0.973423 | 0.000392 | 1.333809 | 0.000140 | 1.622767 | 0.258978 | 0.002054 |
In [5]:
# Calculate and display basic statistics for all columns
stats = df.describe().T
stats['coefficient_of_variation'] = stats['std'] / stats['mean'] * 100 # in percentage
stats['range'] = stats['max'] - stats['min']
# Round all values to 3 decimal places for clarity
stats_rounded = stats.round(3)
# Display statistics for different system types
print("Chilled Water System Statistics:")
chw_cols = [col for col in df.columns if 'CHW' in col]
display(stats_rounded.loc[chw_cols])
print("\nHot Water System Statistics:")
hw_cols = [col for col in df.columns if 'HW' in col]
display(stats_rounded.loc[hw_cols])
Chilled Water System Statistics:
| count | mean | std | min | 25% | 50% | 75% | max | coefficient_of_variation | range | |
|---|---|---|---|---|---|---|---|---|---|---|
| 1A_CHW_FlowRate | 10000.0 | 10.354 | 10.055 | -0.004 | -0.004 | 6.652 | 21.763 | 31.807 | 97.111 | 31.812 |
| 1A_CHW_PumpSpeed | 10000.0 | 70.061 | 1.080 | 70.000 | 70.000 | 70.000 | 70.000 | 90.000 | 1.541 | 20.000 |
| 1A_CHW_SupplyTemp | 10000.0 | 9.872 | 2.357 | 3.236 | 8.294 | 9.890 | 11.013 | 21.515 | 23.873 | 18.279 |
| 1A_CHW_ValvePosition | 10000.0 | 75.940 | 3.304 | 74.801 | 75.199 | 75.211 | 75.768 | 95.295 | 4.351 | 20.493 |
| 1A_CHW_ReturnTemp | 10000.0 | 12.436 | 2.532 | 5.680 | 10.883 | 11.907 | 13.176 | 22.536 | 20.359 | 16.856 |
| 1B_CHW_FlowRate | 10000.0 | 9.348 | 10.125 | -0.007 | 0.006 | 3.985 | 20.564 | 25.188 | 108.310 | 25.195 |
| 1B_CHW_ValvePosition | 10000.0 | 75.493 | 3.277 | 74.454 | 74.798 | 74.842 | 75.168 | 94.947 | 4.341 | 20.492 |
| 1B_CHW_PumpSpeed | 10000.0 | 70.000 | 0.000 | 70.000 | 70.000 | 70.000 | 70.000 | 70.000 | 0.000 | 0.000 |
| 1B_CHW_ReturnTemp | 10000.0 | 11.455 | 2.476 | 5.112 | 9.953 | 10.772 | 12.059 | 21.980 | 21.611 | 16.869 |
| 1B_CHW_SupplyTemp | 10000.0 | 8.800 | 2.320 | 2.001 | 7.291 | 8.914 | 9.872 | 20.372 | 26.365 | 18.370 |
| 1-PLT_CHW_FlowRate | 10000.0 | 30.539 | 2.613 | 15.153 | 30.070 | 31.176 | 31.556 | 33.540 | 8.557 | 18.387 |
| 1-PLT_CHW_ReturnTemp | 10000.0 | 10.903 | 2.699 | 3.930 | 9.221 | 10.757 | 11.940 | 22.723 | 24.755 | 18.793 |
| 1-PLT_CHW_SupplyTemp | 10000.0 | 11.320 | 2.639 | 5.305 | 9.671 | 11.066 | 12.487 | 21.957 | 23.313 | 16.652 |
| 1A_CHW_DeltaT | 10000.0 | 2.564 | 2.765 | -3.670 | 0.565 | 1.501 | 3.631 | 15.199 | 107.847 | 18.869 |
| 1B_CHW_DeltaT | 10000.0 | 2.655 | 2.573 | -3.114 | 0.767 | 1.446 | 4.058 | 17.164 | 96.927 | 20.278 |
| 1-PLT_CHW_DeltaT | 10000.0 | -0.417 | 0.640 | -3.707 | -0.848 | -0.320 | -0.049 | 7.346 | -153.638 | 11.053 |
| 1A_CHW_Energy | 10000.0 | 1.706 | 2.093 | 0.000 | 0.000 | 0.747 | 3.051 | 20.004 | 122.689 | 20.004 |
| 1B_CHW_Energy | 10000.0 | 1.912 | 2.768 | 0.000 | 0.001 | 0.520 | 3.301 | 22.715 | 144.797 | 22.715 |
| 1-PLT_CHW_Energy | 10000.0 | 1.178 | 1.123 | 0.000 | 0.285 | 0.819 | 1.879 | 16.230 | 95.307 | 16.230 |
| CHW_Distribution_Efficiency | 10000.0 | 15.855 | 344.955 | 0.000 | 0.005 | 2.269 | 5.754 | 29448.574 | 2175.688 | 29448.574 |
Hot Water System Statistics:
| count | mean | std | min | 25% | 50% | 75% | max | coefficient_of_variation | range | |
|---|---|---|---|---|---|---|---|---|---|---|
| 1A_CHW_FlowRate | 10000.0 | 10.354 | 10.055 | -0.004 | -0.004 | 6.652 | 21.763 | 31.807 | 97.111 | 31.812 |
| 1A_CHW_PumpSpeed | 10000.0 | 70.061 | 1.080 | 70.000 | 70.000 | 70.000 | 70.000 | 90.000 | 1.541 | 20.000 |
| 1A_CHW_SupplyTemp | 10000.0 | 9.872 | 2.357 | 3.236 | 8.294 | 9.890 | 11.013 | 21.515 | 23.873 | 18.279 |
| 1A_HW_FlowRate | 10000.0 | 3.632 | 4.224 | -0.008 | -0.001 | 0.337 | 8.711 | 9.196 | 116.313 | 9.204 |
| 1A_HW_ValvePosition | 10000.0 | 43.100 | 36.924 | 0.084 | 0.150 | 74.987 | 75.020 | 75.124 | 85.670 | 75.040 |
| 1A_HW_PumpSpeed | 10000.0 | 70.000 | 0.000 | 70.000 | 70.000 | 70.000 | 70.000 | 70.000 | 0.000 | 0.000 |
| 1A_HW_ReturnTemp | 10000.0 | 36.084 | 13.535 | 14.558 | 23.992 | 33.097 | 50.700 | 56.548 | 37.512 | 41.990 |
| 1-PLT_HW_ReturnTemp | 10000.0 | 53.165 | 4.787 | 32.823 | 49.547 | 52.889 | 57.519 | 63.138 | 9.005 | 30.315 |
| 1A_CHW_ValvePosition | 10000.0 | 75.940 | 3.304 | 74.801 | 75.199 | 75.211 | 75.768 | 95.295 | 4.351 | 20.493 |
| 1A_CHW_ReturnTemp | 10000.0 | 12.436 | 2.532 | 5.680 | 10.883 | 11.907 | 13.176 | 22.536 | 20.359 | 16.856 |
| 1A_HW_SupplyTemp | 10000.0 | 38.395 | 15.218 | 12.535 | 21.734 | 42.774 | 53.287 | 59.810 | 39.634 | 47.275 |
| 1B_CHW_FlowRate | 10000.0 | 9.348 | 10.125 | -0.007 | 0.006 | 3.985 | 20.564 | 25.188 | 108.310 | 25.195 |
| 1B_CHW_ValvePosition | 10000.0 | 75.493 | 3.277 | 74.454 | 74.798 | 74.842 | 75.168 | 94.947 | 4.341 | 20.492 |
| 1B_CHW_PumpSpeed | 10000.0 | 70.000 | 0.000 | 70.000 | 70.000 | 70.000 | 70.000 | 70.000 | 0.000 | 0.000 |
| 1B_CHW_ReturnTemp | 10000.0 | 11.455 | 2.476 | 5.112 | 9.953 | 10.772 | 12.059 | 21.980 | 21.611 | 16.869 |
| 1B_CHW_SupplyTemp | 10000.0 | 8.800 | 2.320 | 2.001 | 7.291 | 8.914 | 9.872 | 20.372 | 26.365 | 18.370 |
| 1B_HW_FlowRate | 10000.0 | 3.381 | 3.906 | -0.014 | 0.004 | 0.005 | 7.920 | 8.137 | 115.553 | 8.151 |
| 1B_HW_ValvePosition | 10000.0 | 42.773 | 36.773 | -0.160 | -0.106 | 74.392 | 74.413 | 74.446 | 85.971 | 74.606 |
| 1B_HW_PumpSpeed | 10000.0 | 70.101 | 0.572 | 70.000 | 70.000 | 70.000 | 70.000 | 75.000 | 0.816 | 5.000 |
| 1B_HW_ReturnTemp | 10000.0 | 36.894 | 14.798 | 13.895 | 23.305 | 34.816 | 52.932 | 58.519 | 40.109 | 44.624 |
| 1B_HW_SupplyTemp | 10000.0 | 38.370 | 16.209 | 13.862 | 23.874 | 36.618 | 55.875 | 62.458 | 42.243 | 48.595 |
| 1-PLT_CHW_FlowRate | 10000.0 | 30.539 | 2.613 | 15.153 | 30.070 | 31.176 | 31.556 | 33.540 | 8.557 | 18.387 |
| 1-PLT_CHW_ReturnTemp | 10000.0 | 10.903 | 2.699 | 3.930 | 9.221 | 10.757 | 11.940 | 22.723 | 24.755 | 18.793 |
| 1-PLT_CHW_SupplyTemp | 10000.0 | 11.320 | 2.639 | 5.305 | 9.671 | 11.066 | 12.487 | 21.957 | 23.313 | 16.652 |
| 1-PLT_HW_SupplyTemp | 10000.0 | 52.091 | 5.408 | 34.838 | 47.480 | 51.154 | 57.197 | 62.845 | 10.382 | 28.008 |
| 1A_CHW_DeltaT | 10000.0 | 2.564 | 2.765 | -3.670 | 0.565 | 1.501 | 3.631 | 15.199 | 107.847 | 18.869 |
| 1A_HW_DeltaT | 10000.0 | 2.312 | 5.087 | -7.478 | -1.569 | 0.737 | 4.328 | 26.319 | 220.081 | 33.796 |
| 1B_CHW_DeltaT | 10000.0 | 2.655 | 2.573 | -3.114 | 0.767 | 1.446 | 4.058 | 17.164 | 96.927 | 20.278 |
| 1B_HW_DeltaT | 10000.0 | 1.476 | 2.977 | -10.698 | 0.244 | 1.291 | 2.763 | 29.934 | 201.682 | 40.631 |
| 1-PLT_CHW_DeltaT | 10000.0 | -0.417 | 0.640 | -3.707 | -0.848 | -0.320 | -0.049 | 7.346 | -153.638 | 11.053 |
| 1-PLT_HW_DeltaT | 10000.0 | -1.074 | 2.753 | -9.238 | -3.226 | -0.934 | 0.905 | 12.447 | -256.202 | 21.685 |
| 1A_CHW_Energy | 10000.0 | 1.706 | 2.093 | 0.000 | 0.000 | 0.747 | 3.051 | 20.004 | 122.689 | 20.004 |
| 1A_HW_Energy | 10000.0 | 0.636 | 1.097 | 0.000 | 0.000 | 0.131 | 0.747 | 16.097 | 172.600 | 16.097 |
| 1B_CHW_Energy | 10000.0 | 1.912 | 2.768 | 0.000 | 0.001 | 0.520 | 3.301 | 22.715 | 144.797 | 22.715 |
| 1B_HW_Energy | 10000.0 | 0.720 | 1.160 | 0.000 | 0.000 | 0.001 | 1.132 | 16.561 | 160.979 | 16.561 |
| 1-PLT_CHW_Energy | 10000.0 | 1.178 | 1.123 | 0.000 | 0.285 | 0.819 | 1.879 | 16.230 | 95.307 | 16.230 |
| CHW_Distribution_Efficiency | 10000.0 | 15.855 | 344.955 | 0.000 | 0.005 | 2.269 | 5.754 | 29448.574 | 2175.688 | 29448.574 |
2.2 System Flow Rates and Delta T Analysis¶
In [6]:
# Create time series plots for flow rates
plt.figure(figsize=(14, 7))
flow_cols = [col for col in df.columns if 'FlowRate' in col]
for col in flow_cols:
plt.plot(df.index, df[col], label=f"{col} ({units.get(col, '')})")
plt.title('Plant Flow Rates Over Time')
plt.xlabel('Time')
plt.ylabel('Flow Rate (L/min)')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
# Create time series plots for delta T
plt.figure(figsize=(14, 7))
delta_t_cols = [col for col in df.columns if 'DeltaT' in col]
for col in delta_t_cols:
plt.plot(df.index, df[col], label=f"{col} (°C)")
plt.title('System Delta T Over Time')
plt.xlabel('Time')
plt.ylabel('Delta T (°C)')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
2.3 Interactive Visualization of Plant Operations¶
In [7]:
# Create an interactive time series plot with Plotly
def create_interactive_timeseries(dataframe, column_groups, title):
fig = make_subplots(rows=len(column_groups), cols=1,
subplot_titles=[group['name'] for group in column_groups],
shared_xaxes=True,
vertical_spacing=0.1)
for i, group in enumerate(column_groups):
for col in group['columns']:
unit = units.get(col, '')
fig.add_trace(
go.Scatter(x=dataframe.index, y=dataframe[col], name=f"{col} ({unit})"),
row=i+1, col=1
)
fig.update_layout(
title=title,
height=200 * len(column_groups),
width=1000,
showlegend=True,
legend=dict(orientation="h", yanchor="bottom", y=-0.2)
)
return fig
# Define column groups for visualization
column_groups = [
{
'name': 'Chilled Water Flow Rates',
'columns': [col for col in df.columns if 'CHW' in col and 'FlowRate' in col]
},
{
'name': 'Hot Water Flow Rates',
'columns': [col for col in df.columns if 'HW' in col and 'FlowRate' in col]
},
{
'name': 'Chilled Water Temperatures',
'columns': [col for col in df.columns if 'CHW' in col and ('SupplyTemp' in col or 'ReturnTemp' in col)]
},
{
'name': 'Hot Water Temperatures',
'columns': [col for col in df.columns if 'HW' in col and ('SupplyTemp' in col or 'ReturnTemp' in col)]
},
{
'name': 'Valve Positions',
'columns': [col for col in df.columns if 'ValvePosition' in col]
}
]
# Create and display the plot
fig = create_interactive_timeseries(df, column_groups, 'HVAC Plant Operations Over Time')
fig.show()